import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from wordcloud import WordCloud
import jieba
import numpy as np
from collections import Counter
import os
import re

INPUT_FILE = 'cleaned_comments.csv'  # ← 你的清理后文件
TIME_COLUMN = '评论时间'                   # 时间列名
SCORE_COLUMN = '打分'                      # 评分列名
ID_COLUMN = 'ID'                          # 用户ID列名
COMMENT_COLUMN = '评论'                    # 评论列名

# ----------------------------
# 初始化绘图设置，这里是纯抄的，参数具体代表什么说实话我也不知道，但是我看别人做的要设计一下，我就照着抄了。
# ----------------------------
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans', 'Arial Unicode MS']#这里是为了使用字体，说实话我也不知道这些字体是啥样子，做出来再看吧
plt.rcParams['axes.unicode_minus'] = False#别让符号显示为小横线，虽然我不觉得有人会真的神到在评论上加个负号，但是还是做个准备吧
plt.rcParams['figure.dpi'] = 300#图标的分辨率
plt.rcParams['savefig.dpi'] = 300#保存的时候的分辨率
# 创建输出目录
os.makedirs('analysis_output', exist_ok=True)#想要的东西比较多，所以就让他给我做一个文件夹吧。
#把老子搞好的数据给老子掏出来
df = pd.read_csv(INPUT_FILE, encoding='utf-8-sig')
df[TIME_COLUMN] = pd.to_datetime(df[TIME_COLUMN])

# ==========================
# 1. 时间分布分析（日 & 月）
# ==========================

df['日期'] = df[TIME_COLUMN].dt.date#将日期按照日的方式提取
df['月份'] = df[TIME_COLUMN].dt.to_period('M')#将日期按照月的方式提取

# 每日趋势，以下的所有plt分析都是我到处抄的，因为数据分析比较模块化，或者说基本上除了真正的创造和开发者，所用的文件和代码都是比较模块化，你就找着抄抄抄就完事了。日图和月图都是一样的。
daily = df['日期'].value_counts().sort_index()#数一数每天到底有多少评论，并且按照时间排列。
plt.figure(figsize=(12, 5))#打开一个窗口
daily.plot(kind='line', marker='o', linewidth=1, markersize=2, color='#1f77b4')#绘制图形的时候，我们要注意什么内容。
plt.title('每日评论数量趋势', fontsize=14)#做一下表头
plt.xlabel('日期')#x轴标签
plt.ylabel('评论数量')#y轴标签
plt.grid(True, linestyle='--', alpha=0.6)#添加网格线，虚线，透明度
plt.tight_layout()##自动调整布局
plt.savefig('analysis_output/01_daily_trend.png', bbox_inches='tight')#把图保存起来
plt.close()#关闭窗口，很重要的一步哦

# 每月柱状图
monthly = df['月份'].value_counts().sort_index()
monthly_df = monthly.reset_index()
monthly_df.columns = ['月份', '评论数']
plt.figure(figsize=(10, 5))
sns.barplot(data=monthly_df, x='月份', y='评论数', palette='Blues_d')#有另外一种可行性，就是和日柱状图一样，而不用sns，sns是一个比较专业的玩意，我都写上看看吧，sns只能服务dataframe格式，所以你必须将其转化
plt.title('每月评论数量', fontsize=14)
plt.xlabel('月份')
plt.ylabel('评论数量')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('analysis_output/02_monthly_bar.png', bbox_inches='tight')
plt.close()

# ============================
# 2. 评分分析
# ============================
print("分析评分分布")#进行第二步了，分隔一下，不然不知道哪里出错
scores = df[SCORE_COLUMN]#提取
mean_score = scores.mean()#取最小值
median_score = scores.median()#取中间值
mode_score = scores.mode().iloc[0] if not scores.mode().empty else "无"#计算众数，这串纯属无中生有，其实完全可以用一个scores.mode就行了，只是以防万一出现多个众数，没有众数的情况。

score_pct = scores.value_counts().sort_index() / len(scores) * 100#计算一下每个数据所占比例

with open('analysis_output/score_stats.txt', 'w', encoding='utf-8') as f:
    f.write(f"平均分: {mean_score:.2f}\n")#保留二位小数
    f.write(f"中位数: {median_score:.2f}\n")
    f.write(f"众数: {mode_score}\n")
    f.write(f"总评论数: {len(scores)}\n")


# ============================
# 3. 用户重复评论分析（按 ID）
# ============================
'''
print("分析用户重复评论")

user_counts = df.groupby(ID_COLUMN).size()#按照用户ID计算每个用户评论的次数
repeat_users = user_counts[user_counts > 1]#将重复评论的用户提取出来，看看会不会在刷评论，或者重复观看同一课程

def min_interval(group):
    if len(group) < 2:
        return pd.Timedelta(0)#只评论一次的话，那就无所谓了，最后的答案都是0
    times = group.sort_values()#把多次评论的人们的评论按时间排序
    diffs = times.diff().dropna()#计算两个相邻时间的时间差，并且删除第一个
    return diffs.min()#这个函数还是很有趣的，如果以后打算从事一些数据分析工作，这个函数会用到的

min_ints = df.groupby(ID_COLUMN)[TIME_COLUMN].apply(min_interval)#将每一个对应的用户都做好分组，取出时间序列，每个都进行函数调用
min_ints = min_ints[min_ints > pd.Timedelta(0)]#把0的全部给删了得了
intervals_hours = min_ints.dt.total_seconds() / 86400#把时间差的单位转化为天

plt.figure(figsize=(8, 5))#依旧是做一个树状图？条形图，我前面好像说错了，注意一下。
plt.hist(intervals_hours, bins=30, color='#2ca02c', edgecolor='black', log=True)
plt.title('重复用户最小评论间隔（小时，对数尺度）', fontsize=14)
plt.xlabel('最小间隔（小时）')
plt.ylabel('用户数量（对数）')
plt.tight_layout()
plt.savefig('analysis_output/04_repeat_user_intervals.png', bbox_inches='tight')
plt.close()


with open('analysis_output/repeat_user_stats.txt', 'w', encoding='utf-8') as f:
    total_users = df[ID_COLUMN].nunique()
    repeat_count = len(repeat_users)#输出一个行数的意思
    f.write(f"总用户数: {total_users}\n")
    f.write(f"重复评论用户数: {repeat_count}\n")
    f.write(f"占比: {repeat_count/total_users*100:.2f}%\n")
'''
# ============================
# 4. 文本内容分析（词云）
# ============================
print("生成词云")

all_text = ' '.join(df[COMMENT_COLUMN].astype(str))#把所有的评论全部扔在一起形成一个字符串

# 中文分词
words = jieba.lcut(all_text)#将这个绝大的字符串用jieba进行切分

# 停用词（可扩展）
stop_words = {
    ' ', '', '\n', '\t', '的', '了', '是', '在', '我', '有', '和', '就', '也', '都', '很', '好','老师','课程','非常','爬虫','学习','嵩天','非常',
    '!', '！', '?', '？', '.', '。', ',', '，', ':', '：', ';', '；', '"', "'", '(', ')', '（', '）',
    'a', 'an', 'the', 'and', 'or', 'but', 'to', 'of', 'in', 'on', 'at', 'for', 'is', 'was', 'are'
}#这里是乱选的，后面如果有的话，可以再改直接在这里修改即可，很简单。

filtered = [w.strip() for w in words if len(w.strip()) >= 2 and w not in stop_words and re.search(r'[\u4e00-\u9fa5a-zA-Z0-9]', w)]
#去除词语前后的空白，保留长度大于等于2的此，跳过停用词，并且要保证词语在划分范围内
word_freq = Counter(filtered).most_common(100)#统计出现次数最多的前一百个词
#以下过程我只能解释，你让我硬写我写不出来。
# 尝试不同字体路径（避免词云乱码，词云并不接受中文，这个是前提，所以我们必须要指定一个字体）
font_paths = [
    'simhei.ttf',  # 默认（Linux/Mac 可能没有）
    'C:/Windows/Fonts/simhei.ttf',  # Windows
    '/System/Library/Fonts/PingFang.ttc',  # Mac
    None  # 自动
]

wc_kwargs = {'width': 800, 'height': 600, 'background_color': 'white', 'colormap': 'viridis'}#创建的词云的基本参数

for fp in font_paths:#循环我们所需要的字体
    try:
        if fp is None:
            wc = WordCloud(**wc_kwargs).generate_from_frequencies(dict(word_freq))#直接从字典中生成这一词云
        else:
            wc = WordCloud(font_path=fp, **wc_kwargs).generate_from_frequencies(dict(word_freq))
        break
    except:
        continue

plt.figure(figsize=(10, 8))#依旧是画图
plt.imshow(wc, interpolation='bilinear')#显示词云，并让文字边缘更光滑
plt.axis('off')#隐藏坐标轴
plt.title('评论高频词', fontsize=16)#添加标题
plt.tight_layout()#自动调整布局
plt.savefig('analysis_output/05_wordcloud.png', bbox_inches='tight', dpi=300)#保存高清图片
plt.close()#关闭

with open('analysis_output/top_words.txt', 'w', encoding='utf-8') as f:
    for word, freq in word_freq[:20]:#将前20个高频词写入文本文件
        f.write(f"{word}: {freq}\n")

# ============================
# 5. 评论字数分布
# ============================
print("分析评论字数")

df['字数'] = df[COMMENT_COLUMN].astype(str).apply(len)#对评论列中的每一个数据按照str的格式进行分析，提供长度的数字，形成一个series

plt.figure(figsize=(10, 5))#依旧绘图
plt.hist(df['字数'], bins=50, color='#d62728', edgecolor='black', alpha=0.7)#这里是你按照数据分你所画的图的时候需要注意的东西，这里的使用还是很有意义的。bins是你所绘画区间划分。
plt.axvline(df['字数'].mean(), color='blue', linestyle='--', label=f'平均: {df["字数"].mean():.1f}')
plt.title('评论字数分布', fontsize=14)
plt.xlabel('字数（字符数）')
plt.ylabel('评论数量')
plt.legend()
plt.tight_layout()
plt.savefig('analysis_output/06_word_count_hist.png', bbox_inches='tight')
plt.close()

with open('analysis_output/word_count_stats.txt', 'w', encoding='utf-8') as f:#形成文本将结果放进去
    f.write(f"最小字数: {df['字数'].min()}\n")
    f.write(f"最大字数: {df['字数'].max()}\n")
    f.write(f"平均字数: {df['字数'].mean():.2f}\n")
    f.write(f"中位数字数: {df['字数'].median():.2f}\n")

print("\n🎉 所有分析完成！")
print("📁 结果保存在 'analysis_output' 文件夹中")#这纯粹没啥用，但是我看别人都会加一个觉得很厉害，我也就加一个了。